package dxt.learn.example.jdk17.streamFilter;

import com.alibaba.fastjson2.JSON;

import java.io.*;
import java.util.function.BinaryOperator;

/**
 * 特定于上下文的反序列化过滤器
 * 应用程序现在可以使用 JVM 范围的过滤器工厂配置特定于上下文和动态选择的反序列化过滤器，
 * 调用该过滤器可以为每个单独的反序列化操作选择一个过滤器。
 *
 * 通过一个过滤配置，来告知本次反序列化允许或者禁止操作的类，反序列化时碰到被禁止的类，则会反序列化失败。
 */
public class FilterMain {
    {
        //定义一个过滤器
        var filter = ObjectInputFilter.Config.createFilter("example.*;java.base/*;!*");

    }
    public class FilterInThread implements BinaryOperator<ObjectInputFilter> {

        // ThreadLocal to hold the serial filter to be applied
        private final ThreadLocal<ObjectInputFilter> filterThreadLocal = new ThreadLocal<>();

        //构造一个FilterInThread反序列化过滤器工厂。
        public FilterInThread() {}

        /**
         * The filter factory, which is invoked every time a new ObjectInputStream
         * is created.  If a per-stream filter is already set then it returns a
         * filter that combines the results of invoking each filter.
         *
         * @param curr the current filter on the stream
         * @param next a per stream filter
         * @return the selected filter
         */
        public ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter next) {
            if (curr == null) {
                // Called from the OIS constructor or perhaps OIS.setObjectInputFilter with no current filter
                var filter = filterThreadLocal.get();
                if (filter != null) {
                    // Prepend a filter to assert that all classes have been Allowed or Rejected
                    filter = ObjectInputFilter.rejectUndecidedClass(filter);
                }
                if (next != null) {
                    // Prepend the next filter to the thread filter, if any
                    // Initially this is the static JVM-wide filter passed from the OIS constructor
                    // Append the filter to reject all UNDECIDED results
                    filter = ObjectInputFilter.merge(next, filter);
                    filter = ObjectInputFilter.rejectUndecidedClass(filter);
                }
                return filter;
            } else {
                // Called from OIS.setObjectInputFilter with a current filter and a stream-specific filter.
                // The curr filter already incorporates the thread filter and static JVM-wide filter
                // and rejection of undecided classes
                // If there is a stream-specific filter prepend it and a filter to recheck for undecided
                if (next != null) {
                    next = ObjectInputFilter.merge(next, curr);
                    next = ObjectInputFilter.rejectUndecidedClass(next);
                    return next;
                }
                return curr;
            }
        }

        /**
         * Apply the filter and invoke the runnable.
         *
         * @param filter the serial filter to apply to every deserialization in the thread
         * @param runnable a Runnable to invoke
         */
        public void doWithSerialFilter(ObjectInputFilter filter, Runnable runnable) {
            var prevFilter = filterThreadLocal.get();
            try {
                filterThreadLocal.set(filter);
                runnable.run();
            } finally {
                filterThreadLocal.set(prevFilter);
            }
        }
    }
    //示例
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //常规序列化
        Dog dog = new Dog("哈士奇");
        dog.setPoc(new Poc());
        // 序列化 - 对象转字节数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try  {
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(dog);
        }catch (Exception e){
        }
        byte[] bytes = byteArrayOutputStream.toByteArray();
        // 反序列化 - 字节数组转对象
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Object object = objectInputStream.readObject();
        System.out.println(object.toString());
    }
}
